import os
import sys
import sqlite3
import time
import platform
from datetime import datetime
from PyQt5.QtWidgets import (
    QApplication, QMainWindow, QTreeView, QSplitter, QWidget, 
    QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton, 
    QTextBrowser, QStatusBar, QProgressBar, QFileDialog, QMessageBox
)
from PyQt5.QtCore import Qt, QThread, pyqtSignal
from PyQt5.QtGui import QStandardItemModel, QStandardItem, QFont

class FileScanner(QThread):
    progress_updated = pyqtSignal(int, int, str)
    scan_completed = pyqtSignal()
    
    def __init__(self, db_path, target_path):
        super().__init__()
        self.db_path = db_path
        self.target_path = target_path
        self.total_files = 0
        self.current_count = 0
        self.is_running = True
        
    def run(self):
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS files (
                id INTEGER PRIMARY KEY,
                path TEXT UNIQUE,
                size INTEGER,
                mtime REAL,
                is_dir BOOLEAN,
                preview TEXT,
                file_type TEXT,
                parent_path TEXT
            )
        ''')
        cursor.execute("DELETE FROM files")
        conn.commit()
        
        # 简化文件计数
        self.total_files = sum([len(files) for r, d, files in os.walk(self.target_path)])
        
        # 开始扫描
        self.scan_directory(self.target_path, "", cursor, conn)
        
        conn.commit()
        conn.close()
        self.scan_completed.emit()
    
    def scan_directory(self, path, parent_path, cursor, conn):
        if not self.is_running:
            return
            
        try:
            # 添加当前目录
            self.add_file_to_db(path, True, parent_path, cursor)
            
            # 扫描子目录和文件
            entries = os.listdir(path)
            for entry in entries:
                if not self.is_running:
                    return
                    
                full_path = os.path.join(path, entry)
                if os.path.isdir(full_path):
                    self.scan_directory(full_path, path, cursor, conn)
                else:
                    self.add_file_to_db(full_path, False, path, cursor)
                    self.current_count += 1
                    self.progress_updated.emit(self.current_count, self.total_files, full_path)
                    
                # 定期提交数据库更改
                if self.current_count % 100 == 0:
                    conn.commit()
                    
        except Exception as e:
            print(f"扫描错误: {str(e)}")
    
    def add_file_to_db(self, path, is_dir, parent_path, cursor):
        try:
            stat = os.stat(path)
            size = stat.st_size
            mtime = stat.st_mtime
            file_type = "Directory" if is_dir else os.path.splitext(path)[1]
            
            preview = ""
            if not is_dir and size < 5 * 1024 * 1024:  # 只处理小于5MB的文件
                try:
                    with open(path, 'r', encoding='utf-8', errors='replace') as f:
                        preview = f.read(50)
                except:
                    try:
                        with open(path, 'r', encoding='latin-1', errors='replace') as f:
                            preview = f.read(50)
                    except:
                        preview = "[二进制文件]"
            
            cursor.execute('''
                INSERT INTO files (path, size, mtime, is_dir, preview, file_type, parent_path)
                VALUES (?, ?, ?, ?, ?, ?, ?)
            ''', (path, size, mtime, is_dir, preview, file_type, parent_path))
        except Exception as e:
            print(f"添加文件错误: {str(e)}")
    
    def stop(self):
        self.is_running = False

class FileSystemModel(QStandardItemModel):
    def __init__(self, db_path):
        super().__init__()
        self.db_path = db_path
        self.setHorizontalHeaderLabels(["名称", "类型", "大小", "修改时间"])
        self.load_root()
    
    def load_root(self):
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        cursor.execute("SELECT path FROM files WHERE parent_path = ''")
        roots = cursor.fetchall()
        
        for root in roots:
            path = root[0]
            item = QStandardItem(os.path.basename(path))
            item.setData(path, Qt.UserRole)
            item.setData(True, Qt.UserRole + 1)
            self.appendRow(item)
        
        conn.close()
    
    def load_children(self, parent_item):
        if parent_item.rowCount() > 0:
            return
            
        path = parent_item.data(Qt.UserRole)
        
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        # 获取子目录
        cursor.execute("SELECT path FROM files WHERE parent_path = ? AND is_dir = 1", (path,))
        for dir_path in cursor.fetchall():
            dir_name = os.path.basename(dir_path[0])
            item = QStandardItem(dir_name)
            item.setData(dir_path[0], Qt.UserRole)
            item.setData(True, Qt.UserRole + 1)
            parent_item.appendRow(item)
        
        # 获取文件
        cursor.execute("""
            SELECT path, file_type, size, mtime 
            FROM files 
            WHERE parent_path = ? AND is_dir = 0
        """, (path,))
        for file_path, file_type, size, mtime in cursor.fetchall():
            file_name = os.path.basename(file_path)
            size_str = self.format_size(size)
            mtime_str = datetime.fromtimestamp(mtime).strftime("%Y-%m-%d")
            
            item = QStandardItem(file_name)
            item.setData(file_path, Qt.UserRole)
            item.setData(False, Qt.UserRole + 1)
            
            item_type = QStandardItem(file_type)
            item_size = QStandardItem(size_str)
            item_mtime = QStandardItem(mtime_str)
            
            parent_item.appendRow([item, item_type, item_size, item_mtime])
        
        conn.close()
    
    def format_size(self, size):
        for unit in ['B', 'KB', 'MB', 'GB']:
            if size < 1024.0:
                return f"{size:.1f} {unit}"
            size /= 1024.0
        return f"{size:.1f} GB"

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.db_path = "filescope_simple.db"
        self.init_ui()
        self.scanner = None
        self.current_path = ""
        
    def init_ui(self):
        self.setWindowTitle("简易文件浏览器")
        self.setGeometry(100, 100, 900, 600)
        
        main_widget = QWidget()
        self.setCentralWidget(main_widget)
        main_layout = QVBoxLayout()
        main_widget.setLayout(main_layout)
        
        # 控制栏
        control_layout = QHBoxLayout()
        self.path_edit = QLineEdit(os.path.expanduser("~"))
        control_layout.addWidget(self.path_edit, 3)
        
        self.browse_btn = QPushButton("浏览")
        self.browse_btn.clicked.connect(self.browse_directory)
        control_layout.addWidget(self.browse_btn, 1)
        
        self.scan_btn = QPushButton("扫描")
        self.scan_btn.clicked.connect(self.start_scan)
        control_layout.addWidget(self.scan_btn, 1)
        
        main_layout.addLayout(control_layout)
        
        # 主内容区
        splitter = QSplitter()
        main_layout.addWidget(splitter, 1)
        
        # 左侧树状视图
        self.tree_view = QTreeView()
        self.tree_view.setHeaderHidden(True)
        self.tree_view.clicked.connect(self.on_tree_item_clicked)
        self.model = QStandardItemModel()
        self.tree_view.setModel(self.model)
        splitter.addWidget(self.tree_view)
        
        # 右侧预览区
        right_widget = QWidget()
        right_layout = QVBoxLayout()
        right_widget.setLayout(right_layout)
        
        self.path_label = QLabel("选择文件查看详情")
        right_layout.addWidget(self.path_label)
        
        self.preview_browser = QTextBrowser()
        right_layout.addWidget(self.preview_browser, 1)
        
        btn_layout = QHBoxLayout()
        self.open_btn = QPushButton("打开文件")
        self.open_btn.clicked.connect(self.open_file)
        self.open_btn.setEnabled(False)
        btn_layout.addWidget(self.open_btn)
        
        self.open_folder_btn = QPushButton("打开文件夹")
        self.open_folder_btn.clicked.connect(self.open_folder)
        self.open_folder_btn.setEnabled(False)
        btn_layout.addWidget(self.open_folder_btn)
        right_layout.addLayout(btn_layout)
        
        splitter.addWidget(right_widget)
        splitter.setSizes([300, 600])
        
        # 状态栏
        self.status_bar = QStatusBar()
        self.setStatusBar(self.status_bar)
        
        self.progress_bar = QProgressBar()
        self.progress_bar.setMaximumWidth(200)
        self.progress_bar.setVisible(False)
        self.status_bar.addPermanentWidget(self.progress_bar)
        
        # 初始加载
        self.load_model()
    
    def load_model(self):
        """加载模型"""
        self.model.clear()
        self.model.setHorizontalHeaderLabels(["名称"])
        
        # 添加根项目
        root_item = QStandardItem("计算机")
        self.model.appendRow(root_item)
        
        # 添加驱动器
        if platform.system() == "Windows":
            import win32api
            drives = win32api.GetLogicalDriveStrings().split("\x00")[:-1]
            for drive in drives:
                drive_item = QStandardItem(drive)
                drive_item.setData(drive, Qt.UserRole)
                drive_item.setData(True, Qt.UserRole + 1)
                root_item.appendRow(drive_item)
        else:
            home_item = QStandardItem("主目录")
            home_item.setData(os.path.expanduser("~"), Qt.UserRole)
            home_item.setData(True, Qt.UserRole + 1)
            root_item.appendRow(home_item)
            
            root_item2 = QStandardItem("/")
            root_item2.setData("/", Qt.UserRole)
            root_item2.setData(True, Qt.UserRole + 1)
            root_item.appendRow(root_item2)
    
    def browse_directory(self):
        path = QFileDialog.getExistingDirectory(self, "选择扫描目录", os.path.expanduser("~"))
        if path:
            self.path_edit.setText(path)
    
    def start_scan(self):
        path = self.path_edit.text().strip()
        if not path or not os.path.exists(path):
            QMessageBox.warning(self, "路径错误", "请选择有效的扫描路径")
            return
        
        if self.scanner and self.scanner.isRunning():
            self.scanner.stop()
            self.scanner.wait(1000)
        
        self.scan_btn.setEnabled(False)
        self.scan_btn.setText("扫描中...")
        self.progress_bar.setVisible(True)
        self.progress_bar.setValue(0)
        self.status_bar.showMessage(f"扫描: {path}")
        
        self.scanner = FileScanner(self.db_path, path)
        self.scanner.progress_updated.connect(self.update_progress)
        self.scanner.scan_completed.connect(self.scan_finished)
        self.scanner.start()
    
    def update_progress(self, current, total, file_path):
        self.progress_bar.setMaximum(total)
        self.progress_bar.setValue(current)
        self.status_bar.showMessage(f"扫描: {file_path[:50]}...")
    
    def scan_finished(self):
        self.scan_btn.setText("扫描")
        self.scan_btn.setEnabled(True)
        self.progress_bar.setVisible(False)
        self.status_bar.showMessage("扫描完成")
        
        # 重新加载模型
        self.model = FileSystemModel(self.db_path)
        self.tree_view.setModel(self.model)
        self.tree_view.expandAll()
    
    def on_tree_item_clicked(self, index):
        item = self.model.itemFromIndex(index)
        path = item.data(Qt.UserRole)
        is_dir = item.data(Qt.UserRole + 1)
        
        self.current_path = path
        
        if is_dir:
            # 动态加载子项
            if item.rowCount() == 0:
                self.model.load_children(item)
            
            self.path_label.setText(f"目录: {path}")
            self.preview_browser.clear()
            self.open_btn.setEnabled(False)
            self.open_folder_btn.setEnabled(True)
        else:
            self.path_label.setText(f"文件: {path}")
            self.open_btn.setEnabled(True)
            self.open_folder_btn.setEnabled(True)
            self.show_file_details(path)
    
    def show_file_details(self, path):
        try:
            size = os.path.getsize(path)
            mtime = os.path.getmtime(path)
            _, ext = os.path.splitext(path)
            
            # 显示文件信息
            size_str = self.format_size(size)
            mtime_str = datetime.fromtimestamp(mtime).strftime("%Y-%m-%d %H:%M")
            
            info_text = f"类型: {ext} | 大小: {size_str} | 修改时间: {mtime_str}"
            self.path_label.setText(info_text)
            
            # 显示预览内容
            self.preview_browser.clear()
            
            # 只预览小文本文件
            if size < 1024 * 1024:  # 小于1MB
                try:
                    with open(path, 'r', encoding='utf-8') as f:
                        preview = f.read(500)
                        self.preview_browser.setPlainText(preview)
                except:
                    self.preview_browser.setPlainText("[二进制文件或编码不支持]")
            else:
                self.preview_browser.setPlainText("[文件过大，未加载预览]")
        except Exception as e:
            self.preview_browser.setPlainText(f"错误: {str(e)}")
    
    def format_size(self, size):
        for unit in ['B', 'KB', 'MB', 'GB']:
            if size < 1024.0:
                return f"{size:.1f} {unit}"
            size /= 1024.0
        return f"{size:.1f} TB"
    
    def open_file(self):
        if not self.current_path:
            return
            
        try:
            if platform.system() == "Windows":
                os.startfile(self.current_path)
            elif platform.system() == "Darwin":
                os.system(f"open '{self.current_path}'")
            else:
                os.system(f"xdg-open '{self.current_path}'")
        except Exception as e:
            QMessageBox.critical(self, "打开失败", f"无法打开文件: {str(e)}")
    
    def open_folder(self):
        if not self.current_path:
            return
            
        folder_path = os.path.dirname(self.current_path) if os.path.isfile(self.current_path) else self.current_path
        
        try:
            if platform.system() == "Windows":
                os.startfile(folder_path)
            elif platform.system() == "Darwin":
                os.system(f"open '{folder_path}'")
            else:
                os.system(f"xdg-open '{folder_path}'")
        except Exception as e:
            QMessageBox.critical(self, "打开失败", f"无法打开文件夹: {str(e)}")
    
    def closeEvent(self, event):
        if self.scanner and self.scanner.isRunning():
            self.scanner.stop()
            self.scanner.wait(2000)
        event.accept()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    app.setStyle("Fusion")  # 使用更兼容的样式
    
    # 设置字体
    font = QFont()
    font.setPointSize(10)
    app.setFont(font)
    
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())